www.gusucode.com > VC++ 人脸识别定位、眼睛、嘴巴和鼻识别-源码程序 > VC++ 人脸识别定位、眼睛、嘴巴和鼻识别-源码程序/code/人脸定位实例/FaceDetectDlg.cpp
//Download by http://www.NewXing.com // FaceDetectDlg.cpp : implementation file // #include "stdafx.h" #include "FaceDetect.h" #include "FaceDetectDlg.h" #include "ReplaceDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #include "AddSampleDlg.h" ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CFaceDetectDlg dialog CFaceDetectDlg::CFaceDetectDlg(CWnd* pParent /*=NULL*/) : CDialog(CFaceDetectDlg::IDD, pParent) { //{{AFX_DATA_INIT(CFaceDetectDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CFaceDetectDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CFaceDetectDlg) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CFaceDetectDlg, CDialog) //{{AFX_MSG_MAP(CFaceDetectDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BTN_BINARY, OnBtnBinary) ON_BN_CLICKED(IDC_BTN_EDGE, OnBtnEdge) ON_BN_CLICKED(IDC_BTN_FACEHAIR, OnBtnFacehair) ON_BN_CLICKED(IDC_BTN_HISTOGRAM_FACE, OnBtnHistogramFace) ON_BN_CLICKED(IDC_BTN_HISTOGRAM_H, OnBtnHistogramH) ON_BN_CLICKED(IDC_BTN_HISTOGRAM_HAIR, OnBtnHistogramHair) ON_BN_CLICKED(IDC_BTN_HISTOGRAM_V, OnBtnHistogramV) ON_BN_CLICKED(IDC_BTN_LIKEHOOD, OnBtnLikehood) ON_BN_CLICKED(IDC_BTN_MARK_EYE, OnBtnMarkEye) ON_BN_CLICKED(IDC_BTN_MARK_FACE_1, OnBtnMarkFace1) ON_BN_CLICKED(IDC_BTN_MARK_FACE_2, OnBtnMarkFace2) ON_BN_CLICKED(IDC_BTN_MARK_MOUSE, OnBtnMarkMouse) ON_BN_CLICKED(IDC_BTN_MARK_NOSE, OnBtnMarkNose) ON_BN_CLICKED(IDC_BTN_OPENFILE, OnBtnOpenfile) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CFaceDetectDlg message handlers BOOL CFaceDetectDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here CWnd *pWnd0= GetDlgItem(IDC_BMPSHOW); pDCShow = pWnd0->GetDC(); m_pMainDib = new CDib(); m_tOriPixelArray = NULL; m_tResPixelArray = NULL; m_pResMap = NULL; m_nWndWidth = 0; m_nWndHeight= 0; m_sFileName = ""; m_bSelectByMan = false; m_bLBottonDown = false; m_ManLeft = -1; m_ManRight = -1; m_ManTop = -1; m_ManBottom = -1; m_bFaceOK = false; m_bShowFace = false; m_rFaceRegion.left = m_rFaceRegion.right = m_rFaceRegion.top = m_rFaceRegion.bottom = 0; m_bManualMarkFacial = false; m_bLeftEyeOK = m_bRightEyeOK = m_bLeftNostrilOK = m_bRightNostrilOK = m_bLeftEyeLeftCornerOK = m_bLeftEyeRightCornerOK = m_bRightEyeLeftCornerOK = m_bRightEyeRightCornerOK = m_bLeftMouthCornerOK = m_bRightMouthCornerOK = false; m_bMidMouthOK = m_bMidNoseOK = false; m_LeftEye = m_RightEye = m_LeftEyeLeftCorner = m_LeftEyeRightCorner = m_LeftNostril = m_RightNostril = m_RightEyeLeftCorner = m_RightEyeRightCorner = m_LeftMouthCorner = m_RightMouthCorner = m_MidMouth = m_MidNose = CPoint(-1,-1); return TRUE; // return TRUE unless you set the focus to a control } void CFaceDetectDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CFaceDetectDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); if(m_tResPixelArray==NULL) return; } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CFaceDetectDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } //////////////////////////////////////////////////////////////////////////////// // 画十字形标记 // 参数: pDC-CDC指针 // point-要画的点的坐标 // crColor-标记得颜色 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::DrawCross(CDC *pDC, CPoint point, COLORREF crColor) { CPen pen,*oldPen; pen.CreatePen(PS_SOLID,1,crColor); oldPen = (CPen*)pDC->SelectObject(&pen); pDC->MoveTo(point.x-7,point.y); pDC->LineTo(point.x+7,point.y); pDC->MoveTo(point.x,point.y-7); pDC->LineTo(point.x,point.y+7); pDC->SelectObject(oldPen); pen.DeleteObject(); } //////////////////////////////////////////////////////////////////////////////// // 拷贝位图 // 参数: dest-目标位图指针 // source-源位图指针 //////////////////////////////////////////////////////////////////////////////// bool CFaceDetectDlg::CopyBitMap(RGBQUAD **dest, RGBQUAD **source) { if(source==NULL || dest==NULL) return false; for(int i=0; i<m_nWndHeight; i++) for(int j=0; j<m_nWndWidth; j++) dest[i][j]=source[i][j]; return true; } //////////////////////////////////////////////////////////////////////////////// // 生成新的位图 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::MakeBitMap() { CClientDC ClientDC(pDCShow->GetWindow()); if(m_pResMap!=NULL) delete m_pResMap; m_pResMap=new CBitmap(); m_pResMap->CreateCompatibleBitmap(&ClientDC,m_nWndWidth,m_nWndHeight); CDC dc; dc.CreateCompatibleDC(&ClientDC); dc.SelectObject(m_pResMap); for(int i=0; i<m_nWndHeight; i++) for(int j=0; j<m_nWndWidth; j++) dc.SetPixelV(j,i,RGB(m_tResPixelArray[i][j].rgbRed,m_tResPixelArray[i][j].rgbGreen,m_tResPixelArray[i][j].rgbBlue)); if(m_bFaceOK && m_bShowFace) { CBrush Pen; Pen.CreateSolidBrush(RGB(255,0,0)); dc.FrameRect(m_rFaceRegion,&Pen); Pen.DeleteObject(); } if(m_bLeftEyeOK) DrawCross(&dc,m_LeftEye,RGB(255,0,0)); if(m_bRightEyeOK) DrawCross(&dc,m_RightEye,RGB(255,0,0)); if(m_bLeftEyeLeftCornerOK) DrawCross(&dc,m_LeftEyeLeftCorner,RGB(255,0,255)); if(m_bLeftEyeRightCornerOK) DrawCross(&dc,m_LeftEyeRightCorner,RGB(255,255,0)); if(m_bRightEyeLeftCornerOK) DrawCross(&dc,m_RightEyeLeftCorner,RGB(255,0,255)); if(m_bRightEyeRightCornerOK) DrawCross(&dc,m_RightEyeRightCorner,RGB(255,255,0)); if(m_bLeftNostrilOK) DrawCross(&dc,m_LeftNostril,RGB(0,255,0)); if(m_bRightNostrilOK) DrawCross(&dc,m_RightNostril,RGB(0,255,0)); if(m_bMidNoseOK) DrawCross(&dc,m_MidNose,RGB(0,255,0)); if(m_bLeftMouthCornerOK) DrawCross(&dc,m_LeftMouthCorner,RGB(0,0,255)); if(m_bRightMouthCornerOK) DrawCross(&dc,m_RightMouthCorner,RGB(0,0,255)); if(m_bMidMouthOK) DrawCross(&dc,m_MidMouth,RGB(0,0,255)); dc.DeleteDC(); MyDraw(); } //////////////////////////////////////////////////////////////////////////////////// //读原图的数据 //////////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::LoadOriPixel(CDib *pDib) { BYTE *colorTable; colorTable = (BYTE *)pDib->m_pDibBits; int byteBitCount = pDib->GetBiBitCount()/8; m_tOriPixelArray = new RGBQUAD*[m_nWndHeight]; m_tResPixelArray = new RGBQUAD*[m_nWndHeight]; for(int l=0 ; l<m_nWndHeight; l++) { m_tOriPixelArray[l] = new RGBQUAD[m_nWndWidth]; m_tResPixelArray[l] = new RGBQUAD[m_nWndWidth]; } int count = 0; for(int i=m_nWndHeight-1; i>=0; i--) { for(int j=0; j<m_nWndWidth; j++) { m_tOriPixelArray[i][j].rgbBlue =colorTable[count++]; m_tOriPixelArray[i][j].rgbGreen=colorTable[count++]; m_tOriPixelArray[i][j].rgbRed =colorTable[count++]; m_tOriPixelArray[i][j].rgbReserved = 0; m_tResPixelArray[i][j]=m_tOriPixelArray[i][j]; count += byteBitCount-3; } count += (4-(m_nWndWidth*byteBitCount)%4)%4; } method1 = new CLikelyHood(m_tOriPixelArray,m_nWndWidth,m_nWndHeight); method2 = new CHairFace(m_tOriPixelArray,m_nWndWidth,m_nWndHeight); } //////////////////////////////////////////////////////////////////////////////// // 给位图赋值 // 参数: target-目标位图指针 // Val-要赋予的值 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::SetPixelArray(RGBQUAD **target, int Val) { for(int i=0; i<m_nWndHeight; i++) for(int j=0; j<m_nWndWidth; j++) { target[i][j].rgbRed = target[i][j].rgbBlue = target[i][j].rgbGreen = Val; } } //////////////////////////////////////////////////////////////////////////////// // 边界检测 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::DoLOG(int left, int right, int top, int bottom, RGBQUAD **source, RGBQUAD **target) { int i,j; double **result; result = new double*[m_nWndHeight]; for(int l=0 ; l<m_nWndHeight; l++) { result[l] = new double[m_nWndWidth]; for(j=0; j<m_nWndWidth; j++) result[l][j] = source[l][j].rgbRed; } for(i=0; i<m_nWndHeight; i++) for(j=0; j<m_nWndWidth; j++) { double r,g,temp; temp = source[i][j].rgbGreen+source[i][j].rgbRed+source[i][j].rgbBlue; r = (double)source[i][j].rgbRed/temp; g = (double)source[i][j].rgbGreen/temp; if(g<0.398 && g > 0.246 && r<0.664 && r>0.233 && r>g && g>=0.5*(1-r)) { target[i][j].rgbRed = 255; //face } else target[i][j].rgbRed = 0; } for(i=top+2; i<bottom-2; i++) for(j=left+2; j<right-2; j++) { result[i][j] = (0-2.0/24.0)*((unsigned char)target[i-2][j-2].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i-2][j-1].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i-2][j].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i-2][j+1].rgbRed) + (0-2.0/24.0)*((unsigned char)target[i-2][j+2].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i-1][j-2].rgbRed) + (8.0/24.0) *((unsigned char)target[i-1][j].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i-1][j+2].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i][j-2].rgbRed) + (8.0/24.0) *((unsigned char)target[i][j-1].rgbRed) + (1.0) *((unsigned char)target[i][j].rgbRed) + (8.0/24.0) *((unsigned char)target[i][j+1].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i][j+2].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i+1][j-2].rgbRed) + (8.0/24.0) *((unsigned char)target[i+1][j].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i+1][j+2].rgbRed) + (0-2.0/24.0)*((unsigned char)target[i+2][j-2].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i+2][j-1].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i+2][j].rgbRed) + (0-4.0/24.0)*((unsigned char)target[i+2][j+1].rgbRed) + (0-2.0/24.0)*((unsigned char)target[i+2][j+2].rgbRed); } SetPixelArray(target,255); for(i=top+1; i<bottom-1; i++) for(j=left+1; j<right-1; j++) { int positive = 0; int negtive = 0; for(int m=-1;m<=1;m++) for(int n=-1;n<=1;n++) if(m!=0 || n!=0) { if(result[i+m][j+n]<-5)negtive++; if(result[i+m][j+n]>=5)positive++; } if(positive>2 && negtive>2) { target[i][j].rgbBlue = target[i][j].rgbGreen = target[i][j].rgbRed = 0; } } if(result!=NULL) { for (int i=0 ;i<m_nWndHeight;i++) if(result[i]!=NULL) delete result[i]; delete result; } } //////////////////////////////////////////////////////////////////////////////// // 二值化 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnBinary() { SetCursor(LoadCursor(NULL,IDC_WAIT)); if(!method1->CalBinary()) { AfxMessageBox("请先计算相似度!"); SetCursor(LoadCursor(NULL,IDC_ARROW)); return; } m_bShowFace = false; for(int i=0; i<m_nWndHeight; i++) for(int j=0; j<m_nWndWidth; j++) { m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = (int)(method1->m_pBinaryArray[i][j]*255); } MakeBitMap(); SetCursor(LoadCursor(NULL,IDC_ARROW)); MyDraw(); } //////////////////////////////////////////////////////////////////////////////// // 边缘提取 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnEdge() { if(!m_bFaceOK) { AfxMessageBox("请先确定脸部区域"); return; } //左右眼的水平区域 int nLeft,nRight,nTop,nBottom; nLeft = m_rFaceRegion.left-5 > 0 ? m_rFaceRegion.left-5:0; nRight = m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1; nTop = m_rFaceRegion.top-5 > 0 ? m_rFaceRegion.top-5:0; nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1; //边缘检查 DoLOG(nLeft,nRight,nTop,nBottom,m_tOriPixelArray,m_tResPixelArray); MakeBitMap(); } //////////////////////////////////////////////////////////////////////////////// // 求取头发和脸部区域 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnFacehair() { m_bShowFace = false; SetCursor(LoadCursor(NULL,IDC_WAIT)); method2->MarkHairFace(); for(int i=0; i<m_nWndHeight; i++) for(int j=0; j<m_nWndWidth; j++) { switch(method2->m_pBinaryArray[i][j]) { case 0: m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = 0; m_tResPixelArray[i][j].rgbRed = 255; break; case 1: m_tResPixelArray[i][j].rgbBlue = 255; m_tResPixelArray[i][j].rgbGreen=m_tResPixelArray[i][j].rgbRed=0; break; case 2: m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = 0; break; } } MakeBitMap(); SetCursor(LoadCursor(NULL,IDC_ARROW)); } //////////////////////////////////////////////////////////////////////////////// // 脸部区域直方图 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnHistogramFace() { if(!method2->m_bBinaryOK) { AfxMessageBox("请先计算二值化图!"); return; } m_bShowFace = false; SetCursor(LoadCursor(NULL,IDC_WAIT)); for(int j=0; j<m_nWndWidth; j++) { int count = 0; for(int i=0; i<m_nWndHeight; i++) { if(method2->m_pBinaryArray[i][j] == 0) count++; m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = 255; } for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--) { m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = 0; } } MakeBitMap(); SetCursor(LoadCursor(NULL,IDC_ARROW)); } //////////////////////////////////////////////////////////////////////////////// // 水平方向直方图 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnHistogramH() { if(!method1->m_bBinaryReady) { AfxMessageBox("请先计算二值图"); return; } m_bShowFace = false; SetCursor(LoadCursor(NULL,IDC_WAIT)); for(int j=0; j<m_nWndWidth; j++) { int count = 0; for(int i=0; i<m_nWndHeight; i++) { if(method1->m_pBinaryArray[i][j] == 1) count++; m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = 255; } for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--) { m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = 0; } } MakeBitMap(); SetCursor(LoadCursor(NULL,IDC_ARROW)); } //////////////////////////////////////////////////////////////////////////////// // 头发的直方图 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnHistogramHair() { if(!method2->m_bBinaryOK) { AfxMessageBox("请先计算二值图!"); return; } m_bShowFace = false; SetCursor(LoadCursor(NULL,IDC_WAIT)); for(int j=0; j<m_nWndWidth; j++) { int count = 0; for(int i=0; i<m_nWndHeight; i++) { if(method2->m_pBinaryArray[i][j] == 1) count++; m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = 255; } for(i=m_nWndHeight-1; i>=m_nWndHeight-count;i--) { m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = 0; } } MakeBitMap(); SetCursor(LoadCursor(NULL,IDC_ARROW)); } //////////////////////////////////////////////////////////////////////////////// // 垂直方向的直方图 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnHistogramV() { if(!method1->m_bBinaryReady) { AfxMessageBox("请先计算二值图"); return; } m_bShowFace = false; SetCursor(LoadCursor(NULL,IDC_WAIT)); for(int i=0; i<m_nWndHeight; i++) { int count = 0; for(int j=0; j<m_nWndWidth; j++) { if(method1->m_pBinaryArray[i][j] == 1) count++; m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = 255; } for(j=0; j<count; j++) { m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = 0; } } MakeBitMap(); SetCursor(LoadCursor(NULL,IDC_ARROW)); } //////////////////////////////////////////////////////////////////////////////// // 计算相似度 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnLikehood() { m_bShowFace = false; SetCursor(LoadCursor(NULL,IDC_WAIT)); method1->CalLikeHood(); for(int i=0; i<m_nWndHeight; i++) for(int j=0; j<m_nWndWidth; j++) { m_tResPixelArray[i][j].rgbBlue = m_tResPixelArray[i][j].rgbGreen = m_tResPixelArray[i][j].rgbRed = (int)(method1->m_pLikeliHoodArray[i][j]*255); } MakeBitMap(); SetCursor(LoadCursor(NULL,IDC_ARROW)); } //////////////////////////////////////////////////////////////////////////////// // 标记眼睛区域 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnMarkEye() { int i,j; if(!m_bFaceOK) { AfxMessageBox("请先确定脸部区域"); return; } //左右眼的水平区域 CPoint LeftEyeAreaH(-1,-1),RightEyeAreaH(-1,-1); CPoint LeftEyeAreaV(-1,-1),RightEyeAreaV(-1,-1); int nLeft,nRight,nTop,nBottom; nLeft = m_rFaceRegion.left-5 > 0 ? m_rFaceRegion.left-5:0; nRight = m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1; nTop = m_rFaceRegion.top-5 > 0 ? m_rFaceRegion.top-5:0; nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1; //边缘检查 DoLOG(nLeft,nRight,nTop,nBottom,m_tOriPixelArray,m_tResPixelArray); /////////////////////////////////// //确认两个眼睛的水平区域 ////////////////////////////////// int nSlidWinWidth = (m_rFaceRegion.right - m_rFaceRegion.left)/6/2; int nSlidWinHeight = (m_rFaceRegion.bottom - m_rFaceRegion.top)/15/2; int nMidFaceH = (m_rFaceRegion.right+m_rFaceRegion.left)/2; int nMidFaceV = (m_rFaceRegion.bottom+m_rFaceRegion.top)/2; int *tempArray = new int[m_nWndWidth]; for(i = 0; i<m_nWndWidth; i++) tempArray[i] = 0; for(i=nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--) for(j=m_rFaceRegion.left+nSlidWinWidth; j<m_rFaceRegion.right-nSlidWinWidth; j++) { int count = 0; for(int p= -nSlidWinHeight ;p<nSlidWinHeight;p++) for(int q= -nSlidWinWidth ;q<nSlidWinWidth;q++) { if(m_tResPixelArray[i+p][j+q].rgbRed == 0) count++; } if(count >= nSlidWinWidth*nSlidWinHeight/3) { m_tResPixelArray[i][j].rgbRed = 255; tempArray[j] ++; } } MakeBitMap(); AfxMessageBox("眼睛的区域鉴别"); CList<CPoint,CPoint&> myList1(sizeof(CPoint)); CList<CPoint,CPoint&> myList2(sizeof(CPoint)); int flag = 0; CPoint tPoint(-1,-1); for(i = 0; i<m_nWndWidth; i++) { if(tempArray[i] > 0 && flag ==0) { tPoint.x = i; flag = 1; } if(tempArray[i] == 0 && flag ==1) { tPoint.y = i; myList1.AddTail(tPoint); flag = 0; } } delete tempArray; //去掉长度太小的候选者 for(i=0; i<myList1.GetCount();i++) { CPoint temp(-1,-1); temp = myList1.GetAt(myList1.FindIndex(i)); int minVal = (m_rFaceRegion.right - m_rFaceRegion.left)/20; if((temp.y-temp.x)>=minVal) myList2.AddTail(temp); } myList1.RemoveAll(); //合并相邻很紧的区域 bool quit = 1; while(quit) { bool doJoin = false; for(int i=0; i<myList2.GetCount()-1;i++) { CPoint temp1(-1,-1),temp2(-1,-1); temp1 = myList2.GetAt(myList2.FindIndex(i)); temp2 = myList2.GetAt(myList2.FindIndex(i+1)); if((temp2.x-temp1.y)<=(m_rFaceRegion.right - m_rFaceRegion.left)/40) { temp1.y = temp2.y; myList2.RemoveAt(myList2.FindIndex(i)); myList2.RemoveAt(myList2.FindIndex(i)); if(i == 0) myList2.AddHead(temp1); else myList2.InsertAfter(myList2.FindIndex(i-1),temp1); doJoin = true; break; } } if(!doJoin) quit = 0; } //没有找到眼睛区域 if(myList2.GetCount()<2) { CPoint t=myList2.GetHead(); if((t.y-t.x)>(m_rFaceRegion.right - m_rFaceRegion.left)/2) { LeftEyeAreaH.x = t.x; LeftEyeAreaH.y = t.x+(t.y-t.x)/3; RightEyeAreaH.x = t.y-(t.y-t.x)/3; RightEyeAreaH.y = t.y; } else { AfxMessageBox("确认眼睛位置失败,请手动标定"); return; } } //仅有两个区域 else if(myList2.GetCount()==2) { LeftEyeAreaH = myList2.GetHead(); RightEyeAreaH = myList2.GetTail(); } else //多于两个区域 { int ldis = -100000; int rdis = 100000; for(i=0; i<myList2.GetCount();i++) { CPoint temp(-1,-1); temp = myList2.GetAt(myList2.FindIndex(i)); //右眼 if((temp.x+temp.y)/2 > nMidFaceH) { if(((temp.x+temp.y)/2-nMidFaceH)<rdis) { rdis = (temp.x+temp.y)/2-nMidFaceH; RightEyeAreaH = temp; } } //左眼 else { if(((temp.x+temp.y)/2-nMidFaceH)>ldis) { ldis = (temp.x+temp.y)/2-nMidFaceH; LeftEyeAreaH = temp; } } } } myList2.RemoveAll(); /////////////////////////////////// //确认两个眼睛的垂直区域 ////////////////////////////////// //左眼 if(LeftEyeAreaH != CPoint(-1,-1)) { int *tArray = new int[m_nWndHeight]; int i,j; for(i = 0; i<m_nWndHeight; i++) tArray[i] = 0; for(i=nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--) for(j=LeftEyeAreaH.x; j<=LeftEyeAreaH.y;j++) if(m_tResPixelArray[i][j].rgbRed == 255 && m_tResPixelArray[i][j].rgbGreen == 0) tArray[i] ++; CList<CPoint,CPoint&> myListA(sizeof(CPoint)); CList<CPoint,CPoint&> myListB(sizeof(CPoint)); int flag = 0; CPoint tPoint(-1,-1); for(i = nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--) { if(tArray[i] > 0 && flag ==0) { tPoint.x = i; flag = 1; } if(tArray[i] == 0 && flag ==1) { tPoint.y = i; myListA.AddTail(tPoint); flag = 0; } } delete tArray; //去掉长度太小的候选者 for(i=0; i<myListA.GetCount();i++) { CPoint temp(-1,-1); temp = myListA.GetAt(myListA.FindIndex(i)); int minVal = (m_rFaceRegion.bottom - m_rFaceRegion.top)/100; if((temp.x-temp.y)>=minVal) myListB.AddTail(temp); } myListA.RemoveAll(); //合并相邻很紧的区域 bool quit = 1; while(quit) { bool doJoin = false; for(int i=0; i<myListB.GetCount()-1;i++) { CPoint temp1(-1,-1),temp2(-1,-1); temp1 = myListB.GetAt(myListB.FindIndex(i)); temp2 = myListB.GetAt(myListB.FindIndex(i+1)); if((temp1.y-temp2.x)<=(m_rFaceRegion.bottom - m_rFaceRegion.top)/100) { temp1.y = temp2.y; myListB.RemoveAt(myListB.FindIndex(i)); myListB.RemoveAt(myListB.FindIndex(i)); if(i == 0) myListB.AddHead(temp1); else myListB.InsertAfter(myListB.FindIndex(i-1),temp1); doJoin = true; break; } } if(!doJoin) quit = 0; } if(myListB.GetCount()==0) { AfxMessageBox("无法确定左眼的位置"); } else { LeftEyeAreaV = myListB.GetHead(); double sumX = 0.0; double sumY = 0.0; int sum = 0; m_LeftEyeLeftCorner.x = 100000; m_LeftEyeRightCorner.x = -1; for(i=LeftEyeAreaV.x; i>= LeftEyeAreaV.y;i--) for(j=LeftEyeAreaH.x; j<=LeftEyeAreaH.y;j++) if(m_tResPixelArray[i][j].rgbGreen == 0) { if(j<m_LeftEyeLeftCorner.x) { m_LeftEyeLeftCorner.x = j; m_LeftEyeLeftCorner.y = i; } if(j>m_LeftEyeRightCorner.x) { m_LeftEyeRightCorner.x = j; m_LeftEyeRightCorner.y = i; } sumX += j; sumY += i; sum++; } m_LeftEye.x = (int)(sumX/sum); m_LeftEye.y = (int)(sumY/sum); m_bLeftEyeOK = TRUE; m_bLeftEyeLeftCornerOK = TRUE; m_bLeftEyeRightCornerOK =TRUE; } myListB.RemoveAll(); } //右眼 if(RightEyeAreaH != CPoint(-1,-1)) { int *tArray = new int[m_nWndHeight]; int i,j; for(i = 0; i<m_nWndHeight; i++) tArray[i] = 0; for(i=nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--) for(j=RightEyeAreaH.x; j<=RightEyeAreaH.y;j++) if(m_tResPixelArray[i][j].rgbRed == 255 && m_tResPixelArray[i][j].rgbGreen == 0) tArray[i] ++; CList<CPoint,CPoint&> myListA(sizeof(CPoint)); CList<CPoint,CPoint&> myListB(sizeof(CPoint)); int flag = 0; CPoint tPoint(-1,-1); for(i = nMidFaceV-nSlidWinHeight; i > m_rFaceRegion.top+6*nSlidWinHeight; i--) { if(tArray[i] > 0 && flag ==0) { tPoint.x = i; flag = 1; } if(tArray[i] == 0 && flag ==1) { tPoint.y = i; myListA.AddTail(tPoint); flag = 0; } } delete tArray; //去掉长度太小的候选者 for(i=0; i<myListA.GetCount();i++) { CPoint temp(-1,-1); temp = myListA.GetAt(myListA.FindIndex(i)); int minVal = (m_rFaceRegion.bottom - m_rFaceRegion.top)/100; if((temp.x-temp.y)>=minVal) myListB.AddTail(temp); } myListA.RemoveAll(); //合并相邻很紧的区域 bool quit = 1; while(quit) { bool doJoin = false; for(int i=0; i<myListB.GetCount()-1;i++) { CPoint temp1(-1,-1),temp2(-1,-1); temp1 = myListB.GetAt(myListB.FindIndex(i)); temp2 = myListB.GetAt(myListB.FindIndex(i+1)); if((temp1.y-temp2.x)<=(m_rFaceRegion.bottom - m_rFaceRegion.top)/50) { temp1.y = temp2.y; myListB.RemoveAt(myListB.FindIndex(i)); myListB.RemoveAt(myListB.FindIndex(i)); if(i == 0) myListB.AddHead(temp1); else myListB.InsertAfter(myListB.FindIndex(i-1),temp1); doJoin = true; break; } } if(!doJoin) quit = 0; } if(myListB.GetCount()==0) { AfxMessageBox("无法确定右眼的位置"); } else { if(myListB.GetCount()==1) RightEyeAreaV = myListB.GetHead(); else { CPoint tt = myListB.GetHead(); int index = myListB.GetCount(); while(tt.y > LeftEyeAreaV.x && index > 0) { index --; tt = myListB.GetAt(myListB.FindIndex(myListB.GetCount()-index)); } RightEyeAreaV = tt; } double sumX = 0.0; double sumY = 0.0; int sum = 0; m_RightEyeLeftCorner.x = 100000; m_RightEyeRightCorner.x = -1; for(i=RightEyeAreaV.x; i>=RightEyeAreaV.y;i--) for(j=RightEyeAreaH.x; j<=RightEyeAreaH.y;j++) if(m_tResPixelArray[i][j].rgbGreen == 0) { if(j<m_RightEyeLeftCorner.x) { m_RightEyeLeftCorner.x = j; m_RightEyeLeftCorner.y = i; } if(j>m_RightEyeRightCorner.x) { m_RightEyeRightCorner.x = j; m_RightEyeRightCorner.y = i; } sumX += j; sumY += i; sum++; } m_RightEye.x = (int)(sumX/sum); m_RightEye.y = (int)(sumY/sum); m_bRightEyeOK = TRUE; m_bRightEyeLeftCornerOK = TRUE; m_bRightEyeRightCornerOK =TRUE; } myListB.RemoveAll(); } CopyBitMap(m_tResPixelArray,m_tOriPixelArray); MakeBitMap(); } //////////////////////////////////////////////////////////////////////////////// // 第一种方法标记脸部区域 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnMarkFace1() { if(!method1->m_bBinaryReady) { AfxMessageBox("请先计算二值化图!"); return; } m_bShowFace = true; SetCursor(LoadCursor(NULL,IDC_WAIT)); int *temp = new int[m_nWndWidth]; int max = 0; int pos = -1; for(int j=0; j<m_nWndWidth; j++) { int count = 0; for(int i=0; i<m_nWndHeight; i++) { if(method1->m_pBinaryArray[i][j] == 1) count++; } temp[j] = count; if(count > max) { max = count; pos = j; } } int left,right,l,top,bottom; for(l=pos; l>=0; l--) { if(temp[l]<max*0.2||l==0) { left = l; break; } } for(l=pos; l<m_nWndWidth; l++) { if(temp[l]<max*0.3||l==m_nWndWidth-1) { right = l; break; } } for(int i=0; i<m_nWndHeight; i++) { int count = 0; for(l = left;l<=right;l++) { if(method1->m_pBinaryArray[i][l] == 1) count++; } if(count>=(right-left)*0.5) { top = i; break; } } bottom = (int)(top+(right-left)*1.5)>=m_nWndHeight? m_nWndHeight-1:(int)(top+(right-left)*1.5); CopyBitMap(m_tResPixelArray,m_tOriPixelArray); for(i=top;i<=bottom;i++) { m_tResPixelArray[i][left].rgbBlue=255; m_tResPixelArray[i][left].rgbGreen = m_tResPixelArray[i][left].rgbRed = 0; m_tResPixelArray[i][right].rgbBlue=255; m_tResPixelArray[i][right].rgbGreen = m_tResPixelArray[i][right].rgbRed = 0; } for(j=left;j<=right;j++) { m_tResPixelArray[top][j].rgbBlue=255; m_tResPixelArray[top][j].rgbGreen = m_tResPixelArray[top][j].rgbRed = 0; m_tResPixelArray[bottom][j].rgbBlue=255; m_tResPixelArray[bottom][j].rgbGreen = m_tResPixelArray[bottom][j].rgbRed = 0; } MakeBitMap(); SetCursor(LoadCursor(NULL,IDC_ARROW)); if(m_bFaceOK) { ReplaceDlg dlg; if(dlg.DoModal()==IDOK) { CopyBitMap(m_tResPixelArray,m_tOriPixelArray); CRect rect(left,top,right,bottom); m_rFaceRegion = rect; MakeBitMap(); } } else { m_bFaceOK = true; CopyBitMap(m_tResPixelArray,m_tOriPixelArray); CRect rect(left,top,right,bottom); m_rFaceRegion = rect; MakeBitMap(); } } //////////////////////////////////////////////////////////////////////////////// // 第二种方法标记脸部区域 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnMarkFace2() { if(!method2->m_bBinaryOK) { AfxMessageBox("请先计算二值化图"); return; } m_bShowFace = true; SetCursor(LoadCursor(NULL,IDC_WAIT)); int *numR,*numB, i, j, left,right,top,bottom; int maxnumR = 0, maxnumB = 0; numR = new int[m_nWndWidth]; numB = new int[m_nWndWidth]; for(j=0;j<m_nWndWidth ;j++) { int countR = 0, countB = 0; for(i=0;i<m_nWndHeight;i++) { if(method2->m_pBinaryArray[i][j] == 0) countR++; if(method2->m_pBinaryArray[i][j] == 1) countB++; } if(countR > maxnumR) maxnumR = countR; numR[j] = countR; if(countB > maxnumB) maxnumB = countB; numB[j] = countB; } CList<CPoint,CPoint> myListR(sizeof(CPoint)); CList<CPoint,CPoint> myListB(sizeof(CPoint)); CPoint tempR,tempB; int flagR = 0,flagB = 0; for(j=0;j<m_nWndWidth ;j++) { if(flagR == 0) { if(numR[j]>maxnumR/2) { flagR = 1; tempR.x = j; } } else { if(numR[j]<=maxnumR/2 || j==m_nWndWidth-1) { flagR = 0; tempR.y = j; myListR.AddTail(tempR); } } if(flagB == 0) { if(numB[j]>maxnumB/5) { flagB = 1; tempB.x = j; } } else { if(numB[j]<=maxnumB/5 || j==m_nWndWidth-1) { flagB = 0; tempB.y = j; if(myListB.GetCount() > 1 && (tempB.x-myListB.GetTail().y)<20) myListB.SetAt(myListB.GetTailPosition(),CPoint(myListB.GetTail().x,j)); else myListB.AddTail(tempB); } } } if(numR!=NULL)delete numR; if(numB!=NULL)delete numB; int *hairmark, k; hairmark = new int[m_nWndWidth]; for(j=0;j<m_nWndWidth ;j++) hairmark[j]=0; for(k=0;k<myListB.GetCount();k++) { CPoint temp = myListB.GetAt(myListB.FindIndex(k)); if((temp.y-temp.x)>m_nWndWidth/10) { for(int t = temp.x;t<=temp.y;t++) hairmark[t] = 1; } } for(k=0;k<myListR.GetCount();k++) { CPoint temp = myListR.GetAt(myListR.FindIndex(k)); int templeft=-1; int tempright=-1; if((temp.y-temp.x)>m_nWndWidth/10) { for(int t=temp.x;t<=temp.y;t++) { if(hairmark[t]==1) { int endpos=t+(temp.y-temp.x)/5; if(endpos > temp.y)endpos = temp.y; int yes = 1; for(int q=t;q<=endpos;q++) if(hairmark[q]==0) yes = 0; if(yes == 1) { templeft = t; break; } } } for(int p=temp.y;p>=temp.x;p--) { if(hairmark[p]==1) { int beginpos=p-(temp.y-temp.x)/5; if(beginpos < temp.x)beginpos = temp.x; int yes = 1; for(int q=p;q>=beginpos;q--) if(hairmark[q]==0) yes = 0; if(yes == 1) { tempright = p; break; } } } } if(templeft!=-1 && tempright!=-1) { left = templeft; right = tempright; break; } } if(hairmark !=NULL) delete hairmark; myListR.RemoveAll(); myListB.RemoveAll(); if(left-m_nWndWidth/50>0) left-=(int)m_nWndWidth/50; else left = 0; if(right+m_nWndWidth/40>m_nWndWidth) right=m_nWndWidth-1; else right += m_nWndWidth/40; for(i=0; i<m_nWndHeight; i++) { int count = 0; for(int l = left;l<=right;l++) { if(method2->m_pBinaryArray[i][l] == 0) count++; } if(count>=(right-left)*0.5) { top = i; break; } } bottom = (int)(top+(right-left)*1.5)>=m_nWndHeight? m_nWndHeight-1:(int)(top+(right-left)*1.5); CopyBitMap(m_tResPixelArray,m_tOriPixelArray); for(i=top;i<=bottom;i++) { m_tResPixelArray[i][left].rgbBlue=255; m_tResPixelArray[i][left].rgbGreen = m_tResPixelArray[i][left].rgbRed = 0; m_tResPixelArray[i][right].rgbBlue=255; m_tResPixelArray[i][right].rgbGreen = m_tResPixelArray[i][right].rgbRed = 0; } for(j=left;j<=right;j++) { m_tResPixelArray[top][j].rgbBlue=255; m_tResPixelArray[top][j].rgbGreen = m_tResPixelArray[top][j].rgbRed = 0; m_tResPixelArray[bottom][j].rgbBlue=255; m_tResPixelArray[bottom][j].rgbGreen = m_tResPixelArray[bottom][j].rgbRed = 0; } MakeBitMap(); SetCursor(LoadCursor(NULL,IDC_ARROW)); if(m_bFaceOK) { ReplaceDlg dlg; if(dlg.DoModal()==IDOK) { CopyBitMap(m_tResPixelArray,m_tOriPixelArray); CRect rect(left,top,right,bottom); m_rFaceRegion = rect; MakeBitMap(); } } else { m_bFaceOK = true; CopyBitMap(m_tResPixelArray,m_tOriPixelArray); CRect rect(left,top,right,bottom); m_rFaceRegion = rect; MakeBitMap(); } } //////////////////////////////////////////////////////////////////////////////// // 标记嘴巴 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnMarkMouse() { int i,j; if(!(m_bLeftEyeOK&&m_bRightEyeOK)) { AfxMessageBox("请先确定眼睛"); return; } //左右眼的水平区域 int nLeft,nRight,nTop,nBottom; nLeft = m_rFaceRegion.left-5 > 0 ? m_rFaceRegion.left-5:0; nRight = m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1; nTop = m_rFaceRegion.top-5 > 0 ? m_rFaceRegion.top-5:0; nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1; SetPixelArray(m_tResPixelArray,0); for(i=nTop; i<=nBottom; i++) for(j=nLeft; j<=nRight; j++) { BYTE R,G,B; double temp,dlta; R = m_tOriPixelArray[i][j].rgbRed; G = m_tOriPixelArray[i][j].rgbGreen; B = m_tOriPixelArray[i][j].rgbBlue; if((R==G) && (G==B)) temp = 0; else temp = 0.5*(2*R-G-B)/sqrt((R-G)*(R-G)+(R-B)*(G-B)); dlta = acos(temp); if(dlta < 0.2) { m_tResPixelArray[i][j].rgbRed = 255; } else m_tResPixelArray[i][j].rgbRed = 0; } MakeBitMap(); AfxMessageBox("嘴的肤色鉴定"); //双目斜角 double tanThta; if(m_RightEye.y == m_LeftEye.y) tanThta = 0; else tanThta = (m_RightEye.y - m_LeftEye.y)/(m_RightEye.x - m_LeftEye.x); //双目距离 int EyesDis = (m_RightEye.x-m_LeftEye.x)*(m_RightEye.x-m_LeftEye.x); EyesDis += (m_RightEye.y-m_LeftEye.y)*(m_RightEye.y-m_LeftEye.y); EyesDis = (int)sqrt(EyesDis); //双目平均高度 int EyeV = (m_RightEye.y + m_LeftEye.y)/2; //可能的嘴的区域 int MouthUp = (EyeV+1.0*EyesDis) > nBottom ? nBottom:(int)(EyeV+1.0*EyesDis); int MouthDown = (EyeV+1.5*EyesDis) > nBottom ? nBottom:(int)(EyeV+1.5*EyesDis); int* Y_Arry = new int[MouthDown-MouthUp]; for(i =0 ;i < MouthDown-MouthUp ;i++) Y_Arry[i] = 0; int* X_Arry = new int[EyesDis]; for(i =0 ;i < EyesDis ;i++) X_Arry[i] = 0; for(i = MouthUp ; i < MouthDown; i++) for(j = m_LeftEye.x; j< m_RightEye.x; j++) { if(m_tResPixelArray[i][j].rgbRed == 255) { Y_Arry[i-MouthUp] ++; X_Arry[j-m_LeftEye.x] ++; } } int maxY = 0; for(i =0 ;i < MouthDown-MouthUp ;i++) { if(Y_Arry[i]>maxY) { maxY = Y_Arry[i]; m_MidMouth.y = i+MouthUp - (MouthDown-MouthUp)/10; } } m_LeftMouthCorner.y =(int)(m_MidMouth.y - tanThta*EyesDis/2); m_RightMouthCorner.y =(int)(m_MidMouth.y + tanThta*EyesDis/2); for(i =0 ;i < EyesDis ;i++) { if(X_Arry[i]>0) { m_LeftMouthCorner.x = i+m_LeftEye.x; break; } } for(i = EyesDis -1; i >=0 ;i--) { if(X_Arry[i]>0) { m_RightMouthCorner.x = m_LeftEye.x+i; break; } } //唇中点较薄 int min = 1000000; for(i = (int)(3*EyesDis/7+0.5) ; i <= (int)(4*EyesDis/7+0.5);i++) { if(X_Arry[i]<min) { min = X_Arry[i]; m_MidMouth.x = m_LeftEye.x+i; } } m_MidMouth.x = (int)(m_MidMouth.x+(m_LeftEye.x+EyesDis/2))/2; m_bMidMouthOK = TRUE; m_bLeftMouthCornerOK = TRUE; m_bRightMouthCornerOK = TRUE; CopyBitMap(m_tResPixelArray,m_tOriPixelArray); MakeBitMap(); } //////////////////////////////////////////////////////////////////////////////// // 标记鼻子 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnMarkNose() { int i,j; if(!(m_bLeftEyeOK&&m_bRightEyeOK)) { AfxMessageBox("请先确定眼睛"); return; } //左右眼的水平区域 int nLeft,nRight,nTop,nBottom; nLeft = m_rFaceRegion.left-5 > 0 ? m_rFaceRegion.left-5:0; nRight = m_rFaceRegion.right+5 < m_nWndWidth? m_rFaceRegion.right+5:m_nWndWidth-1; nTop = m_rFaceRegion.top-5 > 0 ? m_rFaceRegion.top-5:0; nBottom = m_rFaceRegion.bottom+5< m_nWndHeight?m_rFaceRegion.bottom+5:m_nWndHeight-1; SetPixelArray(m_tResPixelArray,0); for(i=nTop; i<=nBottom; i++) for(j=nLeft; j<=nRight; j++) { double Y; Y = 0.30*m_tOriPixelArray[i][j].rgbRed+0.59*m_tOriPixelArray[i][j].rgbGreen +0.11*m_tOriPixelArray[i][j].rgbBlue; if(Y<100) { m_tResPixelArray[i][j].rgbRed = 255; } else m_tResPixelArray[i][j].rgbRed = 0; } MakeBitMap(); AfxMessageBox("鼻子的肤色鉴定"); //双目斜角 double tanThta; if(m_RightEye.y == m_LeftEye.y) tanThta = 0; else tanThta = (m_RightEye.y - m_LeftEye.y)/(m_RightEye.x - m_LeftEye.x); //双目距离 int EyesDis = (m_RightEye.x-m_LeftEye.x)*(m_RightEye.x-m_LeftEye.x); EyesDis += (m_RightEye.y-m_LeftEye.y)*(m_RightEye.y-m_LeftEye.y); EyesDis = (int)sqrt(EyesDis); //双目平均高度 int EyeV = (m_RightEye.y + m_LeftEye.y)/2; //可能的鼻子的区域 int NoseUp = (EyeV+0.5*EyesDis) > nBottom ? nBottom:(int)(EyeV+0.5*EyesDis); int NoseDown = (EyeV+0.8*EyesDis) > nBottom ? nBottom:(int)(EyeV+0.8*EyesDis); int* Y_Arry = new int[NoseDown-NoseUp]; for(i =0 ;i < NoseDown-NoseUp ;i++) Y_Arry[i] = 0; int* X_Arry = new int[EyesDis]; for(i =0 ;i < EyesDis ;i++) X_Arry[i] = 0; for(i = NoseUp ; i < NoseDown; i++) for(j = m_LeftEye.x+EyesDis/5; j< m_RightEye.x-EyesDis/5; j++) { if(m_tResPixelArray[i][j].rgbRed == 255) { Y_Arry[i-NoseUp] ++; X_Arry[j-m_LeftEye.x] ++; } } int maxY = 0; for(i =0 ;i < NoseDown-NoseUp ;i++) { if(Y_Arry[i]>maxY) { maxY = Y_Arry[i]; m_MidNose.y = i+NoseUp; } } m_LeftNostril.y =(int)(m_MidNose.y - tanThta*EyesDis/2); m_RightNostril.y =(int)(m_MidNose.y + tanThta*EyesDis/2); for(i =0 ;i < EyesDis ;i++) { if(X_Arry[i]>0) { m_LeftNostril.x = i+m_LeftEye.x; break; } } for(i = EyesDis-1; i >=0 ;i--) { if(X_Arry[i]>0) { m_RightNostril.x = i+m_LeftEye.x; break; } } //唇中点较薄 int min = 1000000; for(i = (int)(EyesDis/3+0.5) ; i <= (int)(2*EyesDis/3+0.5);i++) { if(X_Arry[i]<min) { min = X_Arry[i]; m_MidNose.x = m_LeftEye.x+i; } } m_MidNose.x = (m_MidNose.x+(m_LeftEye.x+EyesDis/2))/2; m_bMidNoseOK = TRUE; m_bLeftNostrilOK = TRUE; m_bRightNostrilOK = TRUE; CopyBitMap(m_tResPixelArray,m_tOriPixelArray); MakeBitMap(); } //////////////////////////////////////////////////////////////////////////////// // 打开文件 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::OnBtnOpenfile() { CAddSampleDlg FileDlg(TRUE, "", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT, "BMP人脸图像(*.bmp)|*.bmp|所有文件(*.*)|*.*||", AfxGetMainWnd()); CString strFile; if (FileDlg.DoModal () != IDOK) return; POSITION pos = FileDlg.GetStartPosition(); strFile = FileDlg.GetNextPathName(pos); m_pMainDib->Open(strFile); m_nWndWidth = m_pMainDib->GetWidth(); m_nWndHeight= m_pMainDib->GetHeight(); m_sFileName = strFile; m_rFaceRegion.left = m_rFaceRegion.right = m_rFaceRegion.top = m_rFaceRegion.bottom = 0; m_bLeftEyeOK = m_bRightEyeOK = m_bLeftNostrilOK = m_bRightNostrilOK = m_bLeftEyeLeftCornerOK = m_bLeftEyeRightCornerOK = m_bRightEyeLeftCornerOK = m_bRightEyeRightCornerOK = m_bLeftMouthCornerOK = m_bRightMouthCornerOK = false; m_bMidMouthOK = m_bMidNoseOK = false; m_LeftEye = m_RightEye = m_LeftEyeLeftCorner = m_LeftEyeRightCorner = m_LeftNostril = m_RightNostril = m_RightEyeLeftCorner = m_RightEyeRightCorner = m_LeftMouthCorner = m_RightMouthCorner = m_MidMouth = m_MidNose = CPoint(-1,-1); SetCursor(LoadCursor(NULL,IDC_WAIT)); //获取像素的值 LoadOriPixel(m_pMainDib); MakeBitMap(); SetCursor(LoadCursor(NULL,IDC_ARROW)); } //////////////////////////////////////////////////////////////////////////////// // 画图 //////////////////////////////////////////////////////////////////////////////// void CFaceDetectDlg::MyDraw() { CRect rc; pDCShow->GetWindow()->GetClientRect(&rc); pDCShow->Rectangle(&rc); CDC dc; CBitmap *pOldBitmap; dc.CreateCompatibleDC(pDCShow); pOldBitmap=dc.SelectObject(m_pResMap); pDCShow->StretchBlt(0,0,m_nWndWidth,m_nWndHeight,&dc,0,0,m_nWndWidth,m_nWndHeight,SRCCOPY); dc.SelectObject(pOldBitmap); dc.DeleteDC(); }